package com.tarena.charging.cost.service;

import cn.tedu.charging.common.pojo.param.ChargingProcessParam;
import cn.tedu.charging.common.pojo.vo.ChargingProcessVO;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.tarena.charging.cost.pojo.po.CostRulePO;
import com.tarena.charging.cost.repository.CostRuleRepository;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class CostService {
    @Autowired
    private CostRuleRepository costRuleRepository;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    public ChargingProcessVO calcCost(ChargingProcessParam param) {
        log.info("开始价格计算逻辑");
        //1.利用仓储层 查询当前param参数对应的计价规则 得到的结果 是一个列表数据
        List<CostRulePO> pos= costRuleRepository.getCostRulesByStationIdAndGunId(param.getStationId(),param.getGunId());
        //2.从这个列表中找到符合当前时间的一个规则 使用到时间判断
        //尖 8-12 14-18 峰18:24 平 12-14 谷 0-8 startTime endTime
        //获取当前系统时间 小时数
        int hour = LocalDateTime.now().getHour();//
        log.info("当前系统小时数:{}",hour);
        CostRulePO rulePO=getProperRule(hour,pos);
        if (rulePO!=null){
            //确实拿到了一个符合当前情况的规则数据
            BigDecimal cost=calculatePrice(rulePO,param);
            //可以对计算价格做100乘法 获取结果 在redis中利用incrby 做叠加 这样就不需要判断是否是初始化 因为如果是初始化 redis是从0开始加的
            //incrby底层处理 必须是string 的value序列化
            int intCost = cost.multiply(new BigDecimal(100)).intValue();//价钱乘100的int数据
            log.info("计算价格 小数点数据:{},100倍:{}",cost,intCost);//用redis的string处理 incrby
            ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
            //key值 应该使用订单编号 每一个订单只有一个叠加价钱结果
            String billKey="bill:cost:final:"+param.getBillId();
            Long increment = opsForValue.increment(billKey, intCost);//叠加的价钱
            //叠加的价钱 重新计算回bigDecimal
            BigDecimal finalCost = new BigDecimal(increment).divide(new BigDecimal(100));
            log.info("计算迭代的最终金额:{}",finalCost);
            //4.封装一个返回值
            ChargingProcessVO vo=new ChargingProcessVO();
            vo.setBillId(param.getBillId());
            vo.setTotalCost(finalCost);
            vo.setPowerFee(rulePO.getPowerFee());
            vo.setGunId(param.getGunId());
            vo.setUserId(param.getUserId());
            vo.setChargingCapacity(param.getChargingCapacity());
            return vo;
        }else{
            log.error("当前计算价格 没有找到规则");
        }
        return null;
    }

    private BigDecimal calculatePrice(CostRulePO po, ChargingProcessParam param) {
        //充电读书 capacity * powerFee
        BigDecimal fee = po.getPowerFee();
        Float capacity = param.getChargingCapacity();
        return fee.multiply(new BigDecimal(capacity));
    }

    private CostRulePO getProperRule(int hour, List<CostRulePO> pos) {
        //1.遍历循环这个pos 对比 当前时间和每一个po中的start end的关系 只能匹配其中一个时间
        List<CostRulePO> filters=pos.stream().filter(po->matchHour(po,hour)).collect(Collectors.toList());
        //2.filter筛选 筛选出来 满足 时间关系 start<hour<end
        if (CollectionUtils.isNotEmpty(filters)&&filters.size()==1){
            return filters.get(0);//返回唯一的一个元素
        }else{
            //不满足筛选的要求 打个日志返回null;
            log.error("当前匹配规则:{},匹配时间:{}",filters,hour);
            return null;
        }

    }

    private boolean matchHour(CostRulePO po, int hour) {
        if (hour>po.getStartTime()&&hour<po.getEndTime()){
            return true;
        }else{
            return false;
        }
    }
}
